package br.com.srv.componentes.rota.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import br.com.srv.commons.service.impl.BasicServiceImpl;
import br.com.srv.componentes.cerca.dao.VeiculoDAOHibernate;
import br.com.srv.componentes.cerca.util.PontosTOComparator;
import br.com.srv.componentes.rota.dao.RotaDAO;
import br.com.srv.componentes.veiculo.service.VeiculoService;
import br.com.srv.model.HoraContratadaTO;
import br.com.srv.model.PontoTO;
import br.com.srv.model.RotaTO;
import br.com.srv.model.StatusEnum;
import br.com.srv.model.VeiculoTO;

public class RotaServiceImpl extends BasicServiceImpl implements RotaService {

	RotaDAO rotaDAO;
	VeiculoDAOHibernate veiculoDAOHibernate;
	VeiculoService veiculoService;

	public void salvar(RotaTO rotaTO) throws Exception {
		
		try {
			saveOrUpdate(rotaTO);
			Set<PontoTO> pontos = rotaTO.getPontos();
			if (pontos != null && !pontos.isEmpty()){
				for (PontoTO pontoTO : pontos) {
					pontoTO.setRotaTO(rotaTO);
				}
			}
			
			Set<PontoTO> pontosFis = rotaTO.getPontosFiscalizacao();
			if (pontosFis != null && !pontosFis.isEmpty()){
				for (PontoTO pontoTO : pontosFis) {
					pontoTO.setRotaTOFis(rotaTO);
				}
			}
		} catch (Exception e) {
			throw new Exception(
					"Ja existe uma linha cadastrada com o nome: " + rotaTO.getNome() + 
					" ou com o c�digo: " + rotaTO.getNome());
		}
	}

	public List<RotaTO> buscarRotas(RotaTO rotaTO) throws Exception {
		return getRotaDAO().buscarRotas(rotaTO);
	}

	public void removerRota(String rotaId) throws Exception {
		RotaTO rotaTO = buscarRotaById(rotaId);
		Set<PontoTO> pontos = rotaTO.getPontos();
		getBasicDAO().deleteAll(pontos);
		getBasicDAO().delete(rotaTO);
		
	}

	public RotaTO buscarRotaById(String rotaId) {		
		return (RotaTO)getBasicDAO().findById(RotaTO.class, new Integer(rotaId));
	}

	public List<RotaTO> buscarRotasAtivas(RotaTO rotaTO) throws Exception {
		rotaTO.setStatus(StatusEnum.ATIVO.getValor());
		return buscarRotas(rotaTO);
	}

	public void salvarVeiculosNaRota(RotaTO rotaTO) throws Exception {
		Set<VeiculoTO> listVeiculos = rotaTO.getVeiculos();
		
		List<VeiculoTO> veiculosASeremExcluidos = getVeiculoDAOHibernate().buscarVeiculosDaRota(rotaTO.getId());
		getVeiculoDAOHibernate().deleteAll(veiculosASeremExcluidos);
		getBasicDAO().saveAll(listVeiculos);
	}

	public List<VeiculoTO> buscarVeiculosDaRota(Integer rotaId) throws Exception {
		List<VeiculoTO> veiculos = new ArrayList<VeiculoTO>();
		
		if (rotaId != null) {		
			veiculos = getVeiculoDAOHibernate().buscarVeiculosDaRota(rotaId);
		}
		
		return veiculos;
	}

	public List<VeiculoTO> buscarVeiculosNaoDaRota(List<VeiculoTO> veiculos, List<VeiculoTO> veiculosDaRota) {
		List<VeiculoTO> result = new ArrayList<VeiculoTO>();
		if (veiculosDaRota.isEmpty()) {
			result = veiculos;
		} else {
			for (VeiculoTO veiculoTO : veiculos) {
				boolean flag = true;
				for (VeiculoTO veiculoDaRota : veiculosDaRota) {
					if (veiculoTO.getRealId().equals(veiculoDaRota.getRealId())) {
						flag = false;
						break;
					}
				}
				
				if (flag) {
					result.add(veiculoTO);
				}
				
			}
		}
		return result;
	}
	
	public Set<VeiculoTO> buscarVeiculosDaRotaComCoordenadas(
			RotaTO rotaTO) throws Exception {
		
		//pegar lista de veiculos
		Set<VeiculoTO> veiculos = rotaTO.getVeiculos();						
		
		//pegar ultimo ponto para cada veiculo		
		//montar TO e colocar na lista de resultado
		if (veiculos != null) {
			for (VeiculoTO veiculoTO : veiculos) {
				
				//Pegar a ultima posicao do veiculo
				Map<String, String> ultimaPosicao =
					getVeiculoService().buscarUltimaPosicaoVeiculo(Integer.toString(veiculoTO.getRealId()));
				
				//seta informações no TO
				VeiculoTO veiculoDaVez = new VeiculoTO();				
				veiculoDaVez.setRealId(new Integer(ultimaPosicao.get("ID").toString()));
				veiculoDaVez.setLongitude(ultimaPosicao.get("X").toString());
				veiculoDaVez.setLatitude(ultimaPosicao.get("Y").toString());
				veiculoDaVez.setDescricao(ultimaPosicao.get("DESC").toString());
				veiculos.add(veiculoTO);
			}
		}
		
		return veiculos;
	}

	public void salvarDadosPonto(PontoTO pontoTO) throws Exception {
		PontoTO aux =
				(PontoTO) getBasicDAO().findById(
						PontoTO.class, pontoTO.getId());
		aux.setDescricao(pontoTO.getDescricao());
		getBasicDAO().save(aux);
	}
	
	public void salvarHoraContratada(HoraContratadaTO horaContratadaTO) throws Exception {
		
//		Integer ultimo = rotaDAO.getUlitimaHoraContratadaPorPonto(
//				horaContratadaTO.getPontoFisTO().getId());
//		horaContratadaTO.setCodigo(++ultimo);
		
		getBasicDAO().save(horaContratadaTO);
	}
	
	public void removerHoraContratada(HoraContratadaTO horaContratadaTO) throws Exception {
		getBasicDAO().delete(horaContratadaTO);
	}
	
	
	public List<PontoTO> carregarPontosIniciais(String id) throws Exception {
		
		List<PontoTO> pontosIniciais = new ArrayList<PontoTO>();
		try {
			RotaTO rota = (RotaTO) getBasicDAO().findById(RotaTO.class, new Integer(id));
			
			pontosIniciais.addAll(rota.getPontosFiscalizacao());
			
			for (PontoTO pontoTO : pontosIniciais) {
				pontoTO.setHorasContratadas(null);
			}
			
			Collections.sort(pontosIniciais, new PontosTOComparator());
		} catch (Exception e) {
			//faz nada.
		}
		
		return pontosIniciais;
	}
	
	public List<PontoTO> carregarPontosFinais(String idRota, String idPontoInicial) throws Exception {
		
		List<PontoTO> pontosFinais = new ArrayList<PontoTO>();
		try {
			RotaTO rotaTO = (RotaTO) getBasicDAO().findById(RotaTO.class, new Integer(idRota));
			List<PontoTO> pontosIniciais = new ArrayList<PontoTO>();
			pontosIniciais.addAll(rotaTO.getPontosFiscalizacao());
			Collections.sort(pontosIniciais, new PontosTOComparator());
			
			PontoTO pontoTO = (PontoTO) getBasicDAO().findById(
					PontoTO.class, new Integer(idPontoInicial));
			
			
			
			Iterator<PontoTO> itPontos = pontosIniciais.iterator();
			PontoTO p = null;
			while (itPontos.hasNext()) {
				p = itPontos.next();
				if (Integer.parseInt(p.getCodigo()) 
						> Integer.parseInt(pontoTO.getCodigo())) {
					pontosFinais.add(p);
				}
			}
				
			for (PontoTO pontoTO2 : pontosFinais) {
				pontoTO2.setHorasContratadas(null);
			}
		
		}catch (Exception e) {
			// faz nada
		}
		
		return pontosFinais;
	}
	
	
	public VeiculoDAOHibernate getVeiculoDAOHibernate() {
		return veiculoDAOHibernate;
	}

	public void setVeiculoDAOHibernate(VeiculoDAOHibernate veiculoDAOHibernate) {
		this.veiculoDAOHibernate = veiculoDAOHibernate;
	}

	public void salvarHorarioContratado(HoraContratadaTO horaContratadaTO) throws Exception {
		getBasicDAO().save(horaContratadaTO);
		
	}
	public RotaDAO getRotaDAO() {
		return rotaDAO;
	}

	public void setRotaDAO(RotaDAO rotaDAO) {
		this.rotaDAO = rotaDAO;
	}

	public VeiculoService getVeiculoService() {
		return veiculoService;
	}

	public void setVeiculoService(VeiculoService veiculoService) {
		this.veiculoService = veiculoService;
	}
	
}
